Skip to content

fix(task): require trust for config-less task includes#10355

Merged
jdx merged 1 commit into
mainfrom
fix/task-include-trust
Jun 12, 2026
Merged

fix(task): require trust for config-less task includes#10355
jdx merged 1 commit into
mainfrom
fix/task-include-trust

Conversation

@jdx

@jdx jdx commented Jun 12, 2026

Copy link
Copy Markdown
Owner

Summary

  • require trust before loading default task include directories from config-less local repos
  • keep global task include paths exempt from the local repo trust gate
  • add an e2e regression that verifies task template rendering does not execute before trust

Tests

  • cargo fmt --check
  • mise run test:e2e e2e/tasks/test_task_include_trust
  • mise run test:e2e e2e/tasks/test_task_untrusted_config_error

This PR was generated by an AI coding assistant.


Note

High Risk
Security fix around trust boundaries and task template execution; behavior changes for untrusted clones that only have mise-tasks directories.

Overview
Closes a security gap where default task include directories (e.g. mise-tasks/, .mise-tasks/) could be loaded and Tera templates rendered (including exec()) in repos with no local mise config, before the user trusts the project.

Task loading now runs trust_check on each include file/dir when discovery is config-less (require_task_include_trust), while includes declared from a trusted mise.toml still skip that extra gate (require_trust: false). Global task include paths under the user/system config dirs remain exempt.

config_root is updated so paths under mise-tasks / .mise-tasks (and related task file layouts) resolve to the project root for trust checks. An e2e test asserts untrusted includes fail with a trust error and never run exec() from task descriptions, including monorepo subdirs with --all.

Reviewed by Cursor Bugbot for commit 306fe66. Bugbot is set up for automated code reviews on this repo. Configure here.

Summary by CodeRabbit

  • Bug Fixes

    • Block untrusted task includes from rendering or executing templates when local config files are absent, including monorepo/subdirectory cases.
    • Improve detection of task-specific directories so they resolve to the correct config root used for trust checks.
  • Tests

    • Added an end-to-end test that verifies untrusted task includes are prevented from running or creating files.

@coderabbitai

coderabbitai Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 2a5f4920-9893-4a28-8a5a-5d2d6df66af2

📥 Commits

Reviewing files that changed from the base of the PR and between 4a1b175 and 306fe66.

📒 Files selected for processing (3)
  • e2e/tasks/test_task_include_trust
  • src/config/config_file/config_root.rs
  • src/config/mod.rs
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/config/config_file/config_root.rs
  • e2e/tasks/test_task_include_trust
  • src/config/mod.rs

📝 Walkthrough

Walkthrough

Adds conditional trust validation when loading task include paths in config-less scenarios and a Bash end-to-end test that verifies untrusted includes are blocked in single-repo and monorepo workflows.

Changes

Task Include Trust Validation

Layer / File(s) Summary
Config root resolution for task dirs
src/config/config_file/config_root.rs
Adjusts config-root discovery to treat mise-tasks/.mise-tasks and certain tasks paths under mise layouts as task-specific roots and updates unit test fixtures.
Task include trust validation implementation
src/config/mod.rs
Imports trust_check, computes require_task_include_trust when no higher-precedence configs exist, threads require_trust into load_tasks_includes, and conditionally calls trust_check_task_include(path, require_trust) before loading resolved include paths and monorepo default include directories.
E2E test for task include trust blocking
e2e/tasks/test_task_include_trust
Bash test that creates untrusted mise-tasks/ci.toml (and monorepo pkg/mise-tasks/ci.toml) containing a Tera exec() payload, runs mise tasks in paranoid/monorepo modes, and asserts the payload is not executed and trust-related output appears.

Sequence Diagram

sequenceDiagram
  participant CLI as mise (CLI)
  participant Loader as load_tasks_in_dir
  participant Includes as load_tasks_includes
  participant Trust as trust_check
  participant FS as FileSystem
  CLI->>Loader: run "mise tasks" / resolve include paths
  Loader->>Includes: resolve default & configured include paths (require_trust?)
  Includes->>Trust: trust_check_task_include(path, require_trust)
  Trust-->>Includes: allowed / denied
  alt allowed
    Includes->>FS: read task include and render templates
  else denied
    Includes->>CLI: surface "not trusted" error
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • jdx/mise#10312: Modifies load_tasks_includes/task-include loading and touches related include/trust logic.
  • jdx/mise#10191: Refactors load_tasks_in_dir and include expansion/ordering, overlapping include-loading behavior.
  • jdx/mise#10219: Changes task-include discovery/loading with overlapping code paths in src/config/mod.rs.

Poem

🐰 I hopped through configs with curious flair,
I sniffed at includes that hid in the lair.
A trust-checked gate kept those templates still,
No sneaky execs, no mischief to spill.
Safe fields for rabbits — hop on, and share!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 22.22% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding trust requirements for task includes in directories without local config files, which is the core security fix implemented across the modified files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/config/mod.rs (1)

2593-2624: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Close the config-less include trust bypass in monorepo subdir loading.

This only protects the load_tasks_in_dir() path. The config-less monorepo fallback at Lines 2025-2041 still calls task_includes_for_dir() and load_tasks_includes() without a trust_check, so mise-tasks/*.toml in a discovered subdirectory can still render templates before trust when tasks are loaded via --all or path hints.

A small helper that applies the same require_task_include_trust && !is_global_task_include_path(...) check before every default-include load would keep the two call paths aligned.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/config/mod.rs` around lines 2593 - 2624, The monorepo subdir fallback
path that calls task_includes_for_dir() and load_tasks_includes() needs the same
include-trust enforcement as the load_tasks_in_dir() path; add the same check
using require_task_include_trust && !is_global_task_include_path(path) before
loading any default/config-less includes and call trust_check(path) when it
fails, or centralize that logic into a small helper (e.g.,
validate_task_include_trust) and use it from both load_tasks_in_dir() and the
monorepo fallback where task_includes_for_dir() / load_tasks_includes() are
invoked so both code paths enforce trust consistently.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@e2e/tasks/test_task_include_trust`:
- Around line 19-31: The test currently discards the mise tasks exit status with
"|| true" and only checks the output for the word "trust"; change the test to
capture the exit code immediately after running mise (store $? into a variable
like "rc") and assert that rc != 0 before checking the output for trust-related
text; locate the command that sets "output=$(MISE_YES=0 MISE_PARANOID=1 mise
tasks 2>&1 || true)" and update the logic around the "output" and "marker"
checks so the script fails if the command succeeded (rc == 0) and only then
proceeds to grep "$output" for the trust message.

---

Outside diff comments:
In `@src/config/mod.rs`:
- Around line 2593-2624: The monorepo subdir fallback path that calls
task_includes_for_dir() and load_tasks_includes() needs the same include-trust
enforcement as the load_tasks_in_dir() path; add the same check using
require_task_include_trust && !is_global_task_include_path(path) before loading
any default/config-less includes and call trust_check(path) when it fails, or
centralize that logic into a small helper (e.g., validate_task_include_trust)
and use it from both load_tasks_in_dir() and the monorepo fallback where
task_includes_for_dir() / load_tasks_includes() are invoked so both code paths
enforce trust consistently.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: bae6cad2-dffd-487f-a564-36a12e4a1140

📥 Commits

Reviewing files that changed from the base of the PR and between 149d5aa and 139147f.

📒 Files selected for processing (2)
  • e2e/tasks/test_task_include_trust
  • src/config/mod.rs

Comment thread e2e/tasks/test_task_include_trust Outdated
@greptile-apps

greptile-apps Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR closes a security gap where default task-include directories (e.g. mise-tasks/) in repos without a local mise.toml could be loaded and Tera-rendered — including exec() calls — before the user trusts the project.

  • A new require_trust parameter is added to load_tasks_includes; it is set to true when no config file exists for the directory and false for config-file-driven includes, with global task paths always exempt via is_global_task_include_path.
  • config_root is extended to recognise mise-tasks/ and .mise-tasks/ as task-directory patterns so trust checks resolve to the correct project root.
  • An e2e test verifies that both single-repo and monorepo config-less task directories are blocked before trust, and that Tera exec() never runs.

Confidence Score: 5/5

The trust gate is correctly placed: it fires only for config-less directories, exempts global task paths, and is bypassed for includes that come from an already-trusted config file. The config_root changes are well-covered by the expanded unit tests.

The core security logic is correct — require_trust is computed as configs.is_empty() in load_tasks_in_dir, and the monorepo branch only reaches require_trust=true inside the !found_config guard. Individual file paths are passed to trust_check rather than directory paths, avoiding the EISDIR scenario raised in earlier review threads. The only rough edge is a cosmetic error message that cites the task file path instead of the project root.

No files require special attention; the error-message presentation in src/config/mod.rs is the only rough edge.

Important Files Changed

Filename Overview
src/config/config_file/config_root.rs Adds mise-tasks and .mise-tasks as recognised task-directory patterns so config_root returns the project root rather than the parent of the include dir; tests updated to cover all new path forms
src/config/mod.rs Adds require_trust flag to load_tasks_includes, inserts per-file trust_check_task_include calls, and wires the flag to false for config-file-driven includes and true when no local config exists; UntrustedConfig receives the individual task file path rather than the computed config_root, producing a slightly misleading error message
e2e/tasks/test_task_include_trust New e2e test covering both the single-repo and monorepo cases; uses MISE_PARANOID=1 and checks for "not trusted" in stderr, but the grep is case-insensitive and could match unrelated log output in edge cases

Reviews (4): Last reviewed commit: "fix(task): require trust for config-less..." | Re-trigger Greptile

Comment thread src/config/mod.rs Outdated
Comment thread e2e/tasks/test_task_include_trust Outdated
Comment thread src/config/mod.rs Outdated
@github-actions

github-actions Bot commented Jun 12, 2026

Copy link
Copy Markdown

Hyperfine Performance

mise x -- echo

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.6.4 x -- echo 21.7 ± 1.3 19.5 26.7 1.01 ± 0.10
mise x -- echo 21.5 ± 1.8 18.8 43.7 1.00

mise env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.6.4 env 19.8 ± 1.0 17.8 25.4 1.00
mise env 20.2 ± 1.1 18.2 25.2 1.02 ± 0.08

mise hook-env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.6.4 hook-env 20.4 ± 1.3 18.1 26.5 1.00
mise hook-env 22.6 ± 2.7 18.5 39.6 1.11 ± 0.15
⚠️ Inconclusive: hook-env measured 11% slower, but the relative uncertainty overlaps the 10% threshold.

mise ls

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.6.4 ls 16.7 ± 0.9 15.3 20.9 1.00
mise ls 17.5 ± 1.1 15.4 22.4 1.05 ± 0.08

xtasks/test/perf

Command mise-2026.6.4 mise Variance
install (cached) 139ms 140ms +0%
ls (cached) 60ms 60ms +0%
bin-paths (cached) 68ms 68ms +0%
task-ls (cached) 128ms 132ms -3%

@jdx jdx force-pushed the fix/task-include-trust branch 3 times, most recently from d409738 to 4a1b175 Compare June 12, 2026 16:50
@jdx jdx force-pushed the fix/task-include-trust branch from 4a1b175 to 306fe66 Compare June 12, 2026 16:59
@jdx jdx merged commit 04b13dc into main Jun 12, 2026
34 checks passed
@jdx jdx deleted the fix/task-include-trust branch June 12, 2026 17:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant